package com.github.baichuan.file.rest.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.VoidResult;
import com.github.baichuan.file.rest.dto.Base64File;
import com.github.baichuan.file.rest.dto.FileIdGenerator;
import com.github.baichuan.utils.SnowFlake;
import com.github.baichuan.web.dto.Result;
import com.google.common.io.Files;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

@Tag(name = "阿里云OSS服务文件服务")
@RestController
@RequestMapping("/{bucket:^(?!.*swagger-ui).*$}")
//@RequestMapping("/{bucket}")
@ConditionalOnBean(OSS.class)
@Slf4j
public class AliyunOssController {
    @Autowired
    private OSS oss;
    @Autowired
    private SnowFlake snowFlake;
    @Autowired
    private Base64.Decoder base64Decoder;

    @Operation(summary = "上传Base64格式文件")
    @PostMapping("/base64/upload")
    public ResponseEntity upload(@PathVariable("bucket") String bucket, @RequestBody @Validated Base64File file){
        if(!oss.doesBucketExist(bucket)){
            return ResponseEntity.badRequest().body(Result.fail("bucket不存在"));
        }

        byte[] bytes = base64Decoder.decode(file.getBase64());

        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType(file.getMime());
        meta.setContentLength(bytes.length);
        meta.addUserMetadata("file-name", UriUtils.encode(file.getName(), "UTF-8"));

        String fileId = StringUtils.isBlank(file.getFileId()) ? snowFlake.nextBase62Id() : file.getFileId();
        PutObjectResult ossResult = oss.putObject(bucket, fileId, new ByteArrayInputStream(bytes), meta);
        if(ossResult.getResponse() != null && ossResult.getResponse().isSuccessful()){
            log.error("阿里云OSS服务返回错误消息：{}", ossResult.getResponse().getErrorResponseAsString());
            return ResponseEntity.ok(Result.fail("文件保存到oss服务发生错误"));
        }

        return ResponseEntity.ok(Result.success("文件保存成功", fileId));
    }

    @Operation(summary = "获取Base64格式文件")
    @GetMapping("/base64/{file}")
    public ResponseEntity getBase64(@PathVariable("bucket") String bucket, @PathVariable("file") String file) throws IOException {
        Base64File base64File = new Base64File();

        try{
            OSSObject ossObject = oss.getObject(bucket, file);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            IOUtils.copy(ossObject.getObjectContent(), bos);

            String fileName = new String(base64Decoder.decode(ossObject.getObjectMetadata().getUserMetadata().get("file-name")), StandardCharsets.UTF_8);
            base64File.setName(fileName);
            base64File.setMime(ossObject.getObjectMetadata().getContentType());
            base64File.setBase64(Base64.getEncoder().encodeToString(bos.toByteArray()));

            return ResponseEntity.ok(base64File);
        } catch (OSSException ex) {
            log.error("获取{}:{}返回错误：{}", bucket, file, ex.getErrorMessage());
            return ResponseEntity.notFound().build();
        }
    }

    @Operation(summary = "表单上传文件")
    @PostMapping({"/upload", "/{folder:[\\w-]+}/upload"})
    public ResponseEntity upload(@PathVariable("bucket") String bucket,
                                 @PathVariable(value = "folder", required = false) String folder,
                                 @RequestParam(value = "fileIdGenerator", required = false) FileIdGenerator fileIdGenerator,
                                 @RequestPart("file") MultipartFile file) throws IOException {
        if (file == null && file.isEmpty()) {
            return ResponseEntity.badRequest().body(Result.fail("文件内容为空"));
        }

        if(!oss.doesBucketExist(bucket)){
            return ResponseEntity.badRequest().body(Result.fail("bucket不存在"));
        }

        String fileId = null;
        if(fileIdGenerator != null && fileIdGenerator == FileIdGenerator.FILE_NAME){
            fileId = file.getOriginalFilename();
        } else {
            String fileExtension = Files.getFileExtension(file.getOriginalFilename());
            fileId = snowFlake.nextBase62Id() + "." + fileExtension;
        }
        byte[] bytes = file.getBytes();

        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType(file.getContentType());
        meta.setContentLength(bytes.length);
        String fileName = StringUtils.isBlank(file.getOriginalFilename()) ? fileId : file.getOriginalFilename();
        meta.addUserMetadata("file-name", UriUtils.encode(fileName, StandardCharsets.UTF_8));

        String key = fileId;
        if(StringUtils.isNotBlank(folder)){
            key = folder + "/" + fileId;
        }

        PutObjectResult ossResult = oss.putObject(bucket, key, new ByteArrayInputStream(bytes), meta);
        if(ossResult.getResponse() != null && ossResult.getResponse().isSuccessful()){
            log.error("阿里云OSS服务返回错误消息：{}", ossResult.getResponse().getErrorResponseAsString());
            return ResponseEntity.ok(Result.fail("文件保存到oss服务发生错误"));
        }

        return ResponseEntity.ok(Result.success("文件保存成功", fileId));
    }

    @Operation(summary = "下载文件")
    @GetMapping({"/download/{file}", "/download/{folder}/{file}",})
    public ResponseEntity download(@PathVariable("bucket") String bucket,
                                   @PathVariable(value = "folder", required = false) String folder,
                                   @PathVariable("file") String file, HttpServletResponse response) throws IOException {
        try{
            String key = file;
            if(StringUtils.isNotBlank(folder)){
                key = folder + "/" + file;
            }

            OSSObject ossObject = oss.getObject(bucket, key);
            response.setContentType(ossObject.getObjectMetadata().getContentType());
            response.setContentLength((int) ossObject.getObjectMetadata().getContentLength());
            response.setHeader("Content-Disposition", "attachment;fileName=" + ossObject.getObjectMetadata().getUserMetadata().get("file-name"));
            IOUtils.copy(ossObject.getObjectContent(), response.getOutputStream());
            return ResponseEntity.ok().build();
        } catch (OSSException ex) {
            log.error("获取{}:{}返回错误：{}", bucket, file, ex.getErrorMessage());
            return ResponseEntity.notFound().build();
        }
    }

    @Operation(summary = "浏览文件")
    @GetMapping({"/{file}", "/{folder}/{file}"})
    public ResponseEntity view(@PathVariable("bucket") String bucket,
                               @PathVariable(value = "folder", required = false) String folder,
                               @PathVariable("file") String file, HttpServletResponse response)
            throws IOException {
        try{
            String key = file;
            if(StringUtils.isNotBlank(folder)){
                key = folder + "/" + file;
            }

            OSSObject ossObject = oss.getObject(bucket, key);
            response.setContentType(ossObject.getObjectMetadata().getContentType());
            response.setContentLength((int) ossObject.getObjectMetadata().getContentLength());
            IOUtils.copy(ossObject.getObjectContent(), response.getOutputStream());
            return ResponseEntity.ok().build();
        } catch (OSSException ex) {
            log.error("获取{}:{}返回错误：{}", bucket, file, ex.getErrorMessage());
            return ResponseEntity.notFound().build();
        }
    }

    @Operation(summary = "删除文件")
    @DeleteMapping({"/{file}", "/{folder}/{file}"})
    public ResponseEntity delete(@PathVariable("bucket") String bucket,
                                 @PathVariable(value = "folder", required = false) String folder,
                                 @PathVariable("file") String file){
        VoidResult ossResult = oss.deleteObject(bucket, folder + "/" + file);
        if(ossResult.getResponse() != null && !ossResult.getResponse().isSuccessful()){
            log.error("阿里云OSS服务返回错误消息：{}", ossResult.getResponse().getErrorResponseAsString());
            return ResponseEntity.ok(Result.fail("文件删除发生错误"));
        }

        return ResponseEntity.ok(Result.success("文件删除成功"));
    }
}
